# -*- coding: utf-8 -*-
"""
@Time : 2021/8/29 10:25
@Author : 华大大不是大大
@File : requests_util.py
description：此文件中包含 解析yaml文件的方法analysis_yaml（），统一替换字符串的方法replace_str（）；统一断言的方法assert_result（）；统一发送请求的方法
"""
import json
import re
import jsonpath
import requests
from Debug_talk import DebugTalk
from util.file_util import write_extract, analysis_parametrize


class Requests:
    # 获取一个session会话对象
    session = requests.session()

    # def __init__(self, yaml_data):
    #     self.yaml_data = self.replace_str(yaml_data)
    #     self.method = str(yaml_data['method']).lower()
    #     self.url = yaml_data['url']
    #     if jsonpath.jsonpath(self.yaml_data, '..headers'):
    #         self.headers = yaml_data['headers']
    #     else:
    #         self.headers = None
    #     if jsonpath.jsonpath(self.yaml_data, '..files'):
    #         self.files = yaml_data['files']
    #     else:
    #         self.files = None

    def analysis_yaml(self, case_info):
        """
        分析yaml文件
        :param case_info:
        :return:
        """
        # 调用替换方法，替换文件中所有的{{}}数据
        case_info = self.replace_str(case_info)
        case_info_keys = dict(case_info).keys()
        print("执行测试用例:{}".center(80, '-').format(case_info['name']))

        # 判断必须要有的以及关键字是否在case_info中
        if 'base_url' in case_info_keys and 'name' in case_info_keys and 'request' in case_info_keys and 'validate' in case_info_keys:
            request_key = case_info['request'].keys()
            if 'method' in request_key and 'url' in request_key:
                # 初始化method
                method = str(case_info['request']['method']).lower()
                del case_info['request']['method']

                # 初始化url，基础路径在这拼接
                url = case_info['request']['url']
                del case_info['request']['url']

                # 初始化headers，如果没有设置为None
                if jsonpath.jsonpath(case_info, '$..headers'):
                    headers = case_info['request']['headers']
                    del case_info['request']['headers']
                else:
                    headers = None

                # 初始化files，如果没有设置为None
                if jsonpath.jsonpath(case_info, '$..files'):
                    files = case_info['request']['files']
                    for key, value in dict(files).items():
                        files[key] = open(value, 'rb')
                    del case_info['request']["files"]
                else:
                    files = None

                # 发送请求
                res = self.send_requests(method=method, url=url, headers=headers, files=files, **case_info['request'])

                # 提取关联数据，可以使用正则提取或者json提取
                if 'extract' in case_info_keys:
                    for key, value in dict(case_info['extract']).items():
                        # 正则提取
                        if '(.*?)' in value or '(.+?)' in value:
                            value = re.search(value, res.text)
                            write_extract({key: value.group(1)})
                        else:
                            # json 提取,jsonpath_value为一个列表，可能为空，也可能为多个
                            jsonpath_value = jsonpath.jsonpath(res.json(), "$.." + str(value))
                            if jsonpath_value:
                                write_extract({key: jsonpath_value[0]})
                            else:
                                print('提取失败。返回结果中没有{}'.format(value))

                # 断言
                assert self.assert_result(case_info['validate'], res)
                return res
            else:
                print('二级关键字必须包括 method和url')
        else:
            print("一级关键字必须有 name，base_url,request,validate.")

    def replace_str(self, replace_data):
        """
        统一替换字符串的方法
        :param replace_data: 数据
        :return:
        """

        # 确认数据不为空，并且转换为字符串格式
        if replace_data and isinstance(replace_data, dict):
            str_yaml = json.dumps(replace_data)
        else:
            str_yaml = replace_data

        # 替换字符串
        for i in range(str_yaml.count('{{')):
            if "{{" and "}}" in str_yaml:
                start_index = str_yaml.index('{{')
                end_index = str_yaml.index('}}', start_index)
                old_str = str_yaml[start_index:end_index + 2]
                func_end_index = old_str.index('(')
                func_name = old_str[2:func_end_index]
                args_value = old_str[func_end_index + 1:old_str.index(')')]
                if ',' in args_value:
                    args_value = args_value.split(',')
                    new_str = getattr(DebugTalk(), func_name)(*args_value)
                else:
                    new_str = getattr(DebugTalk(), func_name)(args_value)
                str_yaml = str_yaml.replace(old_str, str(new_str))

        # 数据转换成dict类型并返回
        replace_data = json.loads(str_yaml)
        return replace_data

    def assert_result(self, yq_result, res):
        assert_flag = True
        # 解析断言
        for list_item in yq_result:
            for assert_name, assert_result in dict(list_item).items():
                if assert_name == 'equals':
                    for equals_key, equals_value in dict(assert_result).items():
                        if equals_key == 'status_code':
                            if res.status_code != equals_value:
                                assert_flag = False
                                print('断言失败! 预期结果为：{}；实际结果为：{}'.format(equals_value, res.status_code))
                        else:
                            jsonpath_list = jsonpath.jsonpath(res.json(), '$..{}'.format(equals_key))
                            if jsonpath_list:
                                if equals_value not in jsonpath_list:
                                    assert_flag = False
                                    print('断言失败! 预期结果为：{}；实际结果为：{}'.format(equals_value, res.status_code))
                elif assert_name == "contains":
                    if assert_result not in str(res.text):
                        assert_flag = False
                        print("断言失败!实际结果中未发现字符串:{};实际结果为:{}.".format(assert_result, res.text))
        return assert_flag

    def send_requests(self, method, url, **kwargs):
        res = self.session.request(method=method, url=url, **kwargs)
        return res
